﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Diagnostics;
using System.Windows.Forms;

namespace Project.Model
{
    public class Bot : Speler
    {
        private BotMoeilijkheid moeilijkheid;
        private BotStrategy strategy;

        private Timer timer;

        private Random rnd;

        private Pion gekozenPion;
        private Pion[] pions;

        public Bot(string naam, Color color, BotMoeilijkheid moeilijkheid, BotStrategy? strategy = null, int time = 10)
            : base(naam, color)
        {
            this.Color = color;
            this.Naam = naam;
            this.moeilijkheid = moeilijkheid;
            this.rnd = new Random();
            if (strategy == null)
            {
                setStrategy();
            }
            else
            {
                this.strategy = (BotStrategy)strategy;
            }
            this.timer = new Timer();
            this.timer.Interval = time;
            this.timer.Tick += new EventHandler(berekenZet2);
        }

        private void setStrategy()
        {
            strategy = (BotStrategy)this.rnd.Next(3);
        }

        public void berekenZet(int mogelijkePionnen)
        {
            this.timer.Start();
            this.pions = new Pion[mogelijkePionnen];
            List<Pion> pionList = new List<Pion>();
            pions = new Pion[mogelijkePionnen];
            for (int i = 0; i < 4; i++)
            {
                if (this.pionnen[i].Move)
                {
                    pionList.Add(this.pionnen[i]);
                }
            }
            this.pions = pionList.ToArray<Pion>();
        }

        public void berekenZet2(object sender, EventArgs e)
        {
            this.timer.Stop();
            if (this.pions.Count() > 0)
            {
                if (this.pions.Count() == 1)
                {
                    this.VerplaatsPion(this.pions[0]);
                }
                else
                {
                    this.gekozenPion = this.kiesPion();
                    this.VerplaatsPion(this.gekozenPion);
                }
            }
            else
            {
                this.Observer.eindeBeurt();
            }
        }

        private Pion kiesPion()
        {
            switch (moeilijkheid)
            {
                case BotMoeilijkheid.MAKKELIJK:
                    return normaleZet();
                case BotMoeilijkheid.MEDIUM:
                    Pion pion;
                    pion = kanEindvakHalen();
                    if (pion == null)
                    {
                        pion = kanSlaan();
                        if (pion == null)
                        {
                            pion = normaleZet();
                        }
                    }
                    return pion;
                case BotMoeilijkheid.MOEILIJK:
                    Pion pion2;
                    pion2 = kanEindvakHalen();
                    if (pion2 == null)
                    {
                        pion2 = kanSlaan();
                        if (pion2 == null)
                        {
                            pion2 = nietInhalen();
                            if (pion2 == null)
                            {
                                pion2 = normaleZet();
                            }
                        }
                    }
                    return pion2;
                default:
                    return normaleZet();
            }
        }

        private Pion pakPion(Pion[] pionnen)
        {
            if (pionnen.Count() <= 0)
            {
                return null;
            }
            else
            {
                int pion = -1;
                switch (strategy)
                {
                    case BotStrategy.FIFO:
                        pion = 0;
                        break;
                    case BotStrategy.LIFO:
                        pion = pionnen.Count() - 1;
                        break;
                    case BotStrategy.RANDOM:
                        pion = rnd.Next(pionnen.Count());
                        break;
                }
                return pionnen[pion];
            }
        }

        private Pion normaleZet()
        {
            return this.pakPion(this.pions);
        }

        private Pion kanEindvakHalen()
        {
            List<Pion> list = new List<Pion>();
            for (int i = 0; i < this.pions.Count(); i++)
            {
                Vak tempVak = this.pions[i].Vak;
                if (tempVak.VakType == VakType.Vak_A || tempVak.VakType == VakType.Vak_Normaal)
                {
                    tempVak = getNextVak(tempVak);
                    if (tempVak.VakType == VakType.Vak_Eind && !tempVak.heeftPion())
                    {
                        list.Add(this.pions[i]);
                    }
                }
            }
            return pakPion(list.ToArray<Pion>());
        }

        private Pion kanSlaan()
        {
            List<Pion> list = new List<Pion>();
            for (int i = 0; i < this.pions.Count(); i++)
            {
                if (this.pions[i].Move)
                {
                    Vak tempVak = this.Pionnen[i].Vak;
                    if (tempVak.VakType == VakType.Vak_A || tempVak.VakType == VakType.Vak_Normaal)
                    {
                        bool backwards = false;
                        for (int j = 0; j < this.Worp; j++)
                        {
                            if (backwards)
                            {
                                tempVak = tempVak.Prev;
                            }
                            else
                            {
                                if (tempVak.NextEind != null && this.isMijnEindvak(tempVak.NextEind))
                                {
                                    tempVak = tempVak.NextEind;
                                }
                                else if (tempVak.Next == null)
                                {
                                    tempVak = tempVak.Prev;
                                    backwards = true;
                                }
                                else
                                {
                                    tempVak = tempVak.Next;
                                }
                            }
                        }
                        if (tempVak.heeftPion()) //kijk of daar al een pion staat
                        {
                            bool eigenPion = false;
                            for (int k = 0; k < this.pions.Count(); k++)
                            {
                                if (this.pions[k] == tempVak.Pion) //Kijk of het mijn eigen pion is
                                {
                                    eigenPion = true;
                                }
                            }
                            if (!eigenPion) //Er is geen eigen pion op het vakje waar ik uitkom
                            {
                                list.Add(this.pions[i]);
                            }
                        }
                    }
                }
            }
            return pakPion(list.ToArray<Pion>());
        }

        private Pion nietInhalen()
        {
            bool[] inhalendePionnen = new bool[this.pions.Count()];
            for (int i = 0; i < this.pions.Count(); i++)
            {
                if (this.pions[i].Move)
                {
                    Vak tempVak = this.pions[i].Vak;
                    if (this.pions[i].Vak.VakType == VakType.Vak_A || this.pions[i].Vak.VakType == VakType.Vak_Normaal)
                    {
                        bool backwards = false;
                        for (int j = 0; j < this.Worp; j++)
                        {
                            if (backwards)
                            {
                                tempVak = tempVak.Prev;
                            }
                            else
                            {
                                if (tempVak.NextEind != null && this.isMijnEindvak(tempVak.NextEind))
                                {
                                    tempVak = tempVak.NextEind;
                                }
                                else if (tempVak.Next == null)
                                {
                                    tempVak = tempVak.Prev;
                                    backwards = true;
                                }
                                else
                                {
                                    tempVak = tempVak.Next;
                                }
                            }
                            if ((tempVak.VakType == VakType.Vak_A || tempVak.VakType == VakType.Vak_Normaal) && tempVak.heeftPion()) //kijk of daar al een pion staat
                            {
                                bool eigenPion = false;
                                for (int k = 0; k < this.pions.Count(); k++)
                                {
                                    if (this.pions[k] == tempVak.Pion) //Kijk of het mijn eigen pion is
                                    {
                                        eigenPion = true;
                                    }
                                }
                                if (!eigenPion) //Er is geen eigen pion op het vakje waar ik uitkom
                                {
                                    inhalendePionnen[i] = true;
                                }
                            }
                        }
                    }
                }
            }
            List<Pion> list = new List<Pion>();
            for (int i = 0; i < inhalendePionnen.Length; i++)
            {
                if (!inhalendePionnen[i])
                {
                    list.Add(this.pions[i]);
                }
            }
            return pakPion(list.ToArray<Pion>());
        }

        public Vak getNextVak(Vak tempVak)
        {
            bool backwards = false;
            for (int j = 0; j < this.Worp; j++)
            {
                if (backwards)
                {
                    tempVak = tempVak.Prev;
                }
                else
                {
                    if (tempVak.NextEind != null && this.isMijnEindvak(tempVak.NextEind))
                    {
                        tempVak = tempVak.NextEind;
                    }
                    else if (tempVak.Next == null)
                    {
                        tempVak = tempVak.Prev;
                        backwards = true;
                    }
                    else
                    {
                        tempVak = tempVak.Next;
                    }
                }
            }
            return tempVak;
        }

        public string getMoeilijkheid()
        {
            string text = "";
            switch (moeilijkheid)
            {
                case BotMoeilijkheid.MAKKELIJK:
                    text = "Makkelijk";
                    break;
                case BotMoeilijkheid.MEDIUM:
                    text = "Medium";
                    break;
                case BotMoeilijkheid.MOEILIJK:
                    text = "Moeilijk";
                    break;
            }
            return text;
        }

        public BotStrategy Strategy
        {
            get { return strategy; }
            set { strategy = value; }
        }

        public BotMoeilijkheid Moeilijkheid
        {
            get { return moeilijkheid; }
            set { moeilijkheid = value; }
        }
    }
}
